package jmine.tec.utils.cripto.key.impl;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;

import jmine.tec.utils.cripto.key.PasswordManager;
import jmine.tec.utils.io.EncodingUtils;
import jmine.tec.utils.io.IOUtils;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;

/**
 * Implementacao base para PasswordManagers que usam um Cipher para descriptar a password
 * 
 * @author takeshi
 */
public abstract class AbstractCipherPasswordManager implements PasswordManager, InitializingBean {

    private Resource passwordResource;

    /**
     * Devolve a chave a ser usada para decriptar
     * 
     * @return {@link Key}
     */
    protected abstract Key getKey();

    /**
     * @return {@link Cipher}
     */
    protected abstract Cipher getCipher();

    /**
     * {@inheritDoc}
     */
    public String getPassword() throws IOException {
        try {
            Cipher cipher = getCipher();
            cipher.init(Cipher.DECRYPT_MODE, getKey());
            byte[] data = cipher.doFinal(IOUtils.readFully(getPasswordResource().getInputStream()));
            return new String(data, EncodingUtils.UTF_CHARSET);
        } catch (InvalidKeyException e) {
            throw new IOException(e.getMessage());
        } catch (IllegalBlockSizeException e) {
            throw new IOException(e.getMessage());
        } catch (BadPaddingException e) {
            throw new IOException("Invalid password file: " + this.getPasswordResource().getDescription());
        }
    }

    /**
     * @return the passwordResource
     */
    public Resource getPasswordResource() {
        return passwordResource;
    }

    /**
     * @param passwordResource the passwordResource to set
     */
    public void setPasswordResource(Resource passwordResource) {
        this.passwordResource = passwordResource;
    }

    /**
     * @throws Exception e
     */
    public void afterPropertiesSet() throws Exception {
        getPassword();
    }

}
